#import RPi.GPIO as GPIO
import wiringpi
from time import *

#
# Output shift register class, intended for use with a TI 74HC595
#
class OutputSR(object):
    def __init__(self,serPin,srclkPin,rclkPin, numOutputs):
        self.serPin = serPin
        self.srclkPin = srclkPin
        self.rclkPin = rclkPin
        self.numOutputs = numOutputs
        self.pinValues = []
        for pin in range(0,numOutputs):
            self.pinValues.append(False)

        self.lastShifted = list(self.pinValues)

        self.io = wiringpi.GPIO(wiringpi.GPIO.WPI_MODE_SYS)
        self.io.pinMode(self.srclkPin,self.io.OUTPUT)
        self.io.pinMode(self.rclkPin,self.io.OUTPUT)
        self.io.pinMode(self.serPin,self.io.OUTPUT)
        self.io.digitalWrite(self.srclkPin,self.io.LOW)
        self.io.digitalWrite(self.rclkPin,self.io.LOW)
        self.io.digitalWrite(self.serPin,self.io.LOW)
        
        #GPIO.setmode(GPIO.BCM)
        #GPIO.setup(self.srclkPin,GPIO.OUT, initial=GPIO.LOW)
        #GPIO.setup(self.rclkPin,GPIO.OUT, initial=GPIO.LOW)
        #GPIO.setup(self.serPin,GPIO.OUT, initial=GPIO.LOW)


    def shiftOne(self,val):
        #GPIO.output(self.srclkPin,GPIO.LOW)
        self.io.digitalWrite(self.srclkPin,self.io.LOW)

        if (val==False):
            #GPIO.output(self.serPin,GPIO.LOW)
            self.io.digitalWrite(self.serPin,self.io.LOW)
        else:
            #GPIO.output(self.serPin,GPIO.HIGH)
            self.io.digitalWrite(self.serPin,self.io.HIGH)

        #GPIO.output(self.srclkPin,GPIO.HIGH)
        self.io.digitalWrite(self.srclkPin,self.io.HIGH)
        #GPIO.output(self.srclkPin,GPIO.LOW)
        self.io.digitalWrite(self.srclkPin,self.io.LOW)


    def shiftAll(self):
        if (self.pinValues!=self.lastShifted):
            #GPIO.output(self.rclkPin,GPIO.LOW)
            self.io.digitalWrite(self.rclkPin,self.io.LOW)

            #for pin in range(1,self.numOutputs+1):
            #    self.shiftOne(self.pinValues[self.numOutputs-pin])

            #Convert list of bools to an int
            output1 = sum(1<<i for i, b in enumerate(self.pinValues[0:8]) if b)
            output2 = sum(1<<i for i, b in enumerate(self.pinValues[8:16]) if b)
            output3 = sum(1<<i for i, b in enumerate(self.pinValues[16:24]) if b)

            self.io.shiftOut(self.serPin,self.srclkPin,wiringpi.MSBFIRST,output3)
            self.io.shiftOut(self.serPin,self.srclkPin,wiringpi.MSBFIRST,output2)
            self.io.shiftOut(self.serPin,self.srclkPin,wiringpi.MSBFIRST,output1)

            #GPIO.output(self.rclkPin,GPIO.HIGH)
            self.io.digitalWrite(self.rclkPin,self.io.HIGH)
            #GPIO.output(self.rclkPin,GPIO.LOW)
            self.io.digitalWrite(self.rclkPin,self.io.LOW)
            self.lastShifted=list(self.pinValues)

    def setPinValue(self,pinNum,pinVal):
        self.pinValues[pinNum]=pinVal

        
#
# Input shift register class, intended for use with TI CD74AC299
# We assumbe S0 pin is being held high, as well as the !MR pin.
# http://www.ti.com/lit/ds/schs288/schs288.pdf
#
class InputSR(object):
    def __init__(self,inputPin,s1Pin,clockPin, numInputs):
        self.inputPin = inputPin
        self.s1Pin = s1Pin
        self.clockPin = clockPin
        self.numInputs = numInputs
        self.pinValues = []
        for pin in range(0,numInputs):
            self.pinValues.append(False)
        #GPIO.setmode(GPIO.BCM)
        #GPIO.setup(self.clockPin,GPIO.OUT, initial=GPIO.LOW)
        #GPIO.setup(self.s1Pin,GPIO.OUT, initial=GPIO.LOW)
        #GPIO.setup(self.inputPin,GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
        self.io = wiringpi.GPIO(wiringpi.GPIO.WPI_MODE_SYS)
        self.io.pinMode(self.clockPin,self.io.OUTPUT)
        self.io.pinMode(self.s1Pin,self.io.OUTPUT)
        self.io.pinMode(self.inputPin,self.io.INPUT)
        self.io.digitalWrite(self.clockPin,self.io.LOW)
        self.io.digitalWrite(self.s1Pin,self.io.LOW)

    # Data gets read in when S1 is brought high,
    # and we do a clock pulse, low to high
    def readPins(self):
        #GPIO.output(self.s1Pin,GPIO.HIGH)
        #GPIO.output(self.clockPin,GPIO.HIGH)
        #GPIO.output(self.clockPin,GPIO.LOW)
        #GPIO.output(self.s1Pin,GPIO.LOW)
        self.io.digitalWrite(self.s1Pin,self.io.HIGH)
        self.io.digitalWrite(self.clockPin,self.io.HIGH)
        self.io.digitalWrite(self.clockPin,self.io.LOW)
        self.io.digitalWrite(self.s1Pin,self.io.LOW)

    # Since S0 is being held high, we can only do a shift right
    # Shift occurs when S1 is low, and clock pulses low to high
    def shiftOne(self):
        #input_val = GPIO.input(self.inputPin)
        input_val = self.io.digitalRead(self.inputPin)
        
        #GPIO.output(self.clockPin,GPIO.LOW)
        #GPIO.output(self.s1Pin,GPIO.LOW)
        self.io.digitalWrite(self.clockPin,self.io.LOW)
        self.io.digitalWrite(self.s1Pin,self.io.LOW)
        #GPIO.output(self.clockPin,GPIO.HIGH)
        #GPIO.output(self.clockPin,GPIO.LOW)
        self.io.digitalWrite(self.clockPin,self.io.HIGH)
        self.io.digitalWrite(self.clockPin,self.io.LOW)

        #return (input_val == GPIO.HIGH)
        return (input_val == self.io.HIGH)

    # This shifts all values out of the shift register and stores
    # the values in the pinValues list
    def shiftAll(self):
        for pin in range(self.numInputs-1,-1,-1): #In order to go from top to bottom
            self.pinValues[pin]=self.shiftOne()

    def getPinValues(self):
        return self.pinValues
            
